package com.catchman.config;

import com.catchman.shiro.UserRealm;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.cache.CacheManager;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ShiroConfig {

    /**
     * DefaultAdvisorAutoProxyCreator实现Spring自动代理,，由Advisor决定对哪些类的方法进行AOP代理。
     * @return
     */
    @Bean
    public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        /**
         * setUsePrefix(false)用于解决一个奇怪的bug。在引入spring aop的情况下。
         * 在@Controller注解的类的方法中加入@RequiresRole注解，会导致该方法无法映射请求，导致返回404。
         * 加入这项配置能解决这个bug
         */
        creator.setUsePrefix(true);
        return creator;
    }

    /**
     * 从spring CacheManager中取得EhCacheManager，如果不配置缓存则不必须
     * @param cacheManager
     * @return
     */
    @Bean
    public EhCacheManager getEhCacheManager(CacheManager cacheManager) {
        if (cacheManager instanceof EhCacheCacheManager) {
            //从spring 获取 net.sf.ehcache.CacheManager
            EhCacheManager ehCacheManager = new EhCacheManager();
            ehCacheManager.setCacheManager(((EhCacheCacheManager) cacheManager).getCacheManager());
            return ehCacheManager;
        }
        return null;

    }


    /**
     * 配置realm，必须
     * @param ehCacheManager
     * @return
     */
    @Bean
    public Realm realm(EhCacheManager ehCacheManager) {
        UserRealm userRealm = new UserRealm();
        // 设置 shiro 的缓存管理
        // 此处只配置了认证缓存，本框架所有用户信息（包括权限信息）均是在认证时查询数据库，故只需配置认证缓存，减少访问数据库次数
        // 配置了缓存后，更新用户相关信息后需要使得缓存失效
        userRealm.setCacheManager(ehCacheManager);
        userRealm.setAuthenticationCacheName("shiroCache");
        userRealm.setAuthenticationCachingEnabled(true);
        return userRealm;
    }

    /**
     * 这里统一做鉴权，即判断哪些请求路径需要用户登录，哪些请求路径不需要用户登录。
     * 这里只做鉴权，不做权限控制，因为权限用注解来做。
     */
    @Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
        //哪些请求可以匿名访问
        chainDefinition.addPathDefinition("/auth/login", "anon");
        chainDefinition.addPathDefinition("/auth/logout", "anon");
        chainDefinition.addPathDefinition("/page/401", "anon");
        chainDefinition.addPathDefinition("/page/403", "anon");
        chainDefinition.addPathDefinition("/page/index", "anon");
        //swagger2 控制访问相关资源
//        chainDefinition.addPathDefinition("/sys/monitor/swagger", "anon");
//        chainDefinition.addPathDefinition("/swagger-ui.html", "anon");
        chainDefinition.addPathDefinition("/swagger-resources/**", "anon");
        chainDefinition.addPathDefinition("/v2/api-docs", "anon");
        chainDefinition.addPathDefinition("/webjars/springfox-swagger-ui/**", "anon");

        //druid sql监控相关资源
//        chainDefinition.addPathDefinition("/sys/monitor/druid", "anon");
        chainDefinition.addPathDefinition("/druid/js/**", "anon");
        chainDefinition.addPathDefinition("/druid/css/**", "anon");

        // logged in users with the 'document:read' permission
//        chain.addPathDefinition("/docs/**", "authc, perms[document:read]");
        //除了以上的请求外，其它请求都需要登录
        chainDefinition.addPathDefinition("/**", "authc");
        return chainDefinition;
    }


}
